package jmine.tec.json;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang.StringEscapeUtils;

/**
 * JSONObject eh um mapa de String para JSON
 * 
 * @author takeshi
 */
public class JSONObject extends AbstractJSONObject {

    private final Map<String, JSON> properties = new LinkedHashMap<String, JSON>();

    /**
     * Construtor
     */
    public JSONObject() {
    }

    /**
     * Constructor
     * 
     * @param values values
     */
    public JSONObject(Map<String, JSON> values) {
        this.properties.putAll(values);
    }

    /**
     * {@inheritDoc}
     */
    public Collection<String> getPropertyNames() {
        return new ArrayList<String>(this.properties.keySet());
    }

    /**
     * {@inheritDoc}
     */
    public void setProperty(String propertyName, JSON value) {
        this.properties.put(propertyName, value);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, JSON> getAllProperties() {
        return new LinkedHashMap<String, JSON>(this.properties);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<JSON> getPropertyValues() {
        return new ArrayList<JSON>(this.properties.values());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getSize() {
        return this.properties.size();
    }

    /**
     * {@inheritDoc}
     */
    public JSON getProperty(String propertyName) {
        final JSON json = this.properties.get(propertyName);
        if (json == null) {
            return JSONNullObject.INSTANCE;
        }
        return json;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return this.properties.toString();
    }

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((this.properties == null) ? 0 : this.properties.hashCode());
        return result;
    }

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        JSONObject other = (JSONObject) obj;
        if (this.properties == null) {
            if (other.properties != null) {
                return false;
            }
        } else if (!this.properties.equals(other.properties)) {
            return false;
        }
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public Writer write(Writer writer) throws IOException {
        writer.append("{");
        Iterator<String> it = this.properties.keySet().iterator();
        if (it.hasNext()) {
            this.writeProperty(writer, it.next());
        }
        while (it.hasNext()) {
            writer.write(',');
            this.writeProperty(writer, it.next());
        }
        writer.append("}");
        return writer;
    }

    /**
     * Escreve a propriedade dada
     * 
     * @param writer writer
     * @param key key
     * @throws IOException IOException
     */
    private void writeProperty(Writer writer, String key) throws IOException {
        writer.write('\"');
        writer.write(StringEscapeUtils.escapeJavaScript(key));
        writer.write('\"');
        writer.write(':');
        this.properties.get(key).write(writer);
    }

}
